iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0
Modern Web

剛入行就一人重新打造公司前端系統?系列 第 25

Day 25 - 寫 React 為何會觸發瘋狂的重新渲染?

  • 分享至 

  • xImage
  •  

初次學習使用 React hooks 時,曾經不小心觸發無限的重新渲染迴圈然後暴打 API,心驚了一下,幸好 server 沒事XD 雖然那次的教訓讓我學會如何避免此類問題,但後來在其他情況下又遇到無限渲染的問題。這說明對於 React hooks 的使用還不夠熟悉,尤其是 useStateuseEffect 的觀念不夠熟悉,那這次鐵人賽就特別再多查一些可能會觸發的情況,然後整理起來~

1. 使用 useState 時直接在頁面中呼叫 setState

function App() {
  const [count, setCount] = useState(0);

  setCount(1); // infinite loop

  return ...
}

造成原因:

React 在每次渲染時,若偵測到狀態的變化就會觸發 re-render,而 setState 每次都會導致狀態更新。因此,若在元件的渲染過程中直接執行 setCount,就會進入無限的渲染迴圈。

正確寫法:

應將 setState 放在 useEffect 中,並使用空的 dependencies 陣列,確保只在初次渲染時更新狀態。

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(1);
  }, [])
  

  return ...
}

2. useEffect 中造成的無限渲染

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(count + 1) // infinite loop
  }, [count])

  return ...
}

造成原因:

這個問題出現在 useEffectdependencies 中直接依賴 count,當 setCount 更新 count 後,會觸發元件重新渲染,進而再次執行 useEffect,這樣的循環會導致無限的渲染。

正確寫法:

setCount 中使用 Day 23 時提到的「傳入更新函式」來更新狀態,確保狀態更新基於前一個值,而不依賴當前的 count

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(previousCount => previousCount + 1)
  }, [])

  return ...
}

3. 不正確的設定 event handlers

export default function App() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={setCount(1)}>Submit</button> // infinite loop
  );
}

造成原因:

在這個例子中,setCount(1) 會在每次元件渲染時立即執行,而不是等待點擊事件觸發。因此,每次渲染時都會更新 count,從而導致無限的重新渲染。

正確寫法:

setCount 包裝在箭頭函式中,確保它只在按鈕點擊時才執行。

export default function App() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(1)}>Submit</button> // infinite loop
  );
}

4. useEffect 中 dependencies 不穩定

function App() {
  const [count, setCount] = useState(0);
  let unstableValue = Math.random(); // 每次渲染都會變化

  useEffect(() => {
    console.log('unstableValue 改變時執行');
  }, [unstableValue]); // 依賴於不穩定的變數

  return ...
}

造成原因:

每次渲染時,unstableValue 都會生成新的值,這會導致 useEffect 被不斷觸發,從而產生無限的副作用執行迴圈。

正確寫法:

useEffect 的依賴應該是穩定且可以預期變化的變數,通常是 useStateuseReducer 管理的狀態。

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('count 改變時執行');
  }, [count]); // 依賴穩定的狀態變數

  return ...
}

參考資料


上一篇
Day 24 - useEffect 是拿來做什麼的?
下一篇
Day 26 - useState 的異步更新問題
系列文
剛入行就一人重新打造公司前端系統?27
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言